﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NDesk.Options;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using sqlDALgen.Loaders;
using System.IO;

namespace sqlDALgen
{
    class Program
    {
        static void Main(string[] args)
        {
            String name = null;
            String alias = null;
            String csNamespace = "dal";
            String schema = "dbo";
            String connectionString = null;
            String outputFolder = "out";
            String entityType = "table";
            String scriptsFolder = "";

            var templates = new List<String>();

            var data = new TemplateData();
            data.Add("args", new TemplateData());

            var optionSet = new OptionSet()
                .Add("custom", c => entityType = "custom")
                .Add("enum", e => entityType = "enum");
            optionSet.Parse(args);

            templates.Add(String.Format(@"scripts\templates\dal\code\{0}\entity\t_entity_dto.xml", entityType));
            templates.Add(String.Format(@"scripts\templates\dal\code\{0}\adapter\t_dto_adapter.xml", entityType));

            optionSet = new OptionSet()
                .Add("name=|n=", v => name = v)
                .Add("alias=|a=", v => alias = v)
                .Add("namespace=|ns=", v => csNamespace = v)
                .Add("schema=|s=", v => schema = v)
                .Add("i", i =>
                    {
                        templates.Add(String.Format(@"scripts\templates\dal\storedProcs\{0}\insert\p_insertProc.xml", entityType));
                        templates.Add(String.Format(@"scripts\templates\dal\code\{0}\service\t_service_insert.xml", entityType));
                    })
                .Add("d=", d =>
                {
                    templates.Add(String.Format(@"scripts\templates\dal\storedProcs\{0}\delete\p_deleteProc.xml", entityType));
                    data["args"].Add("delete", new TemplateData());
                    foreach (var i in d.Split(','))
                        data["args"]["delete"].Add(i, new TemplateData { { "name", TemplateData.ValueNode(i) } });
                })
                .Add("u=", u =>
                {
                    templates.Add(String.Format(@"scripts\templates\dal\storedProcs\{0}\update\p_updateProc.xml", entityType));
                    templates.Add(String.Format(@"scripts\templates\dal\code\{0}\service\t_service_update.xml", entityType));
                    data["args"].Add("update", new TemplateData());
                    foreach (var i in u.Split(','))
                        data["args"]["update"].Add(i, new TemplateData { { "name", TemplateData.ValueNode(i) } });
                })
                .Add("g=", g =>
                {
                    templates.Add(String.Format(@"scripts\templates\dal\storedProcs\{0}\get\p_getProc.xml", entityType));
                    templates.Add(String.Format(@"scripts\templates\dal\code\{0}\service\t_service_get.xml", entityType));
                    data["args"].Add("get", new TemplateData());

                    if (!String.IsNullOrEmpty(g))
                        templates.Add(String.Format(@"scripts\templates\dal\storedProcs\{0}\get\p_getWithKeyProc.xml", entityType));

                    foreach (var i in g.Split(','))
                        data["args"]["get"].Add(i, new TemplateData { { "name", TemplateData.ValueNode(i) } });
                })
                .Add("o=|outputFolder=", o => outputFolder = o)
                .Add("c=|connectionString=", c => connectionString = c)
                .Add("sf=|scriptsFolder=", s => scriptsFolder = s);
            var otherArgs = optionSet.Parse(args);

            for (var i = 0; i < templates.Count; i++)
                templates[i] = Path.Combine(scriptsFolder, templates[i]);

            data.Add("entity", new TemplateData { 
                { "name", TemplateData.ValueNode(name) },
                { "namespace", TemplateData.ValueNode(csNamespace) },
                { "schema", TemplateData.ValueNode(schema) }, 
                { "alias", TemplateData.ValueNode((alias ?? name)) } 
            });

            data.Add("static", new TemplateData { 
                { "scriptsFolder", TemplateData.ValueNode(scriptsFolder) },
                { "outputFolder", TemplateData.ValueNode(outputFolder) },
                { "storedProcNamePrefix", TemplateData.ValueNode("p_") },
                { "storedProcNameSuffix", TemplateData.ValueNode("") },
            });

            Console.WriteLine(String.Format("-----------------------------------------------------"));
            Console.WriteLine(String.Format("Initiating Code Generation"));
            Console.WriteLine(String.Format("-----------------------------------------------------"));
            Console.WriteLine(String.Format(""));
            Console.WriteLine(String.Format("Scripts Folder: {0}", scriptsFolder));
            Console.WriteLine(String.Format("Output Folder: {0}", outputFolder));
            Console.WriteLine(String.Format("Entity>> name: '{0}', alias: '{1}', entity_type: '{2}', db_schema: '{3}', namespace: '{4}'", name, alias, entityType, schema, csNamespace));
            Console.WriteLine(String.Format(""));

            Console.WriteLine(String.Format("Fetching data for entity: '{0}'", name));

            if (entityType == "table")
                data.Add("data", new TableLoader().Load(name, schema, connectionString));
            else
                data.Add("data", new CustomEntityLoader().Load(Path.Combine(scriptsFolder, String.Format(@"scripts\entities\{0}", name)), schema, connectionString));

            Console.WriteLine(String.Format("Data fetched successfully for entity: '{0}'", name));
            Console.WriteLine(String.Format(""));

            data.Add("action", new TemplateData { 
                                { "name", TemplateData.ValueNode("") }
                            });

            foreach (var template in templates)
            {
                if (template.Contains("getWithKey"))
                    data["action"]["name"] = TemplateData.ValueNode("get");
                else if (template.Contains("get"))
                    data["action"]["name"] = TemplateData.ValueNode("get_all");
                else if (template.Contains("insert"))
                    data["action"]["name"] = TemplateData.ValueNode("insert");
                else if (template.Contains("update"))
                    data["action"]["name"] = TemplateData.ValueNode("update");
                else if (template.Contains("delete"))
                    data["action"]["name"] = TemplateData.ValueNode("delete");

                Console.WriteLine(String.Format("Generating code for template '{0}'", template));

                TemplateRenderer.Render(template, data, Path.Combine(outputFolder, template.IndexOf("code") == -1 ? "storedProc" : "code"));

                Console.WriteLine(String.Format("Code generated at: '{0}'", template));
                Console.WriteLine(String.Format(""));
            }

            Console.WriteLine(String.Format("-----------------------------------------------------"));
            Console.WriteLine(String.Format("Code Generation successfully completed"));
            Console.WriteLine(String.Format("-----------------------------------------------------"));
            Console.WriteLine(String.Format(""));

            Console.ReadLine();
        }
    }
}